package com.bestcem.xm.member.grpc.client;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.bestcem.bp.grpc.v1.base.Page;
import com.bestcem.bp.xm.user.grpc.v1.services.UserServiceGrpc;
import com.bestcem.bp.xm.user.grpc.v1.services.*;
import com.bestcem.xm.common.core.constant.GrpcClientNames;
import com.bestcem.xm.common.core.domain.web.ServiceResult;
import com.bestcem.xm.label.constant.Constants;
import com.bestcem.xm.member.service.dto.GroupNodeDTO;
import com.bestcem.xm.member.service.dto.OrganizationDTO;
import com.bestcem.xm.member.util.DateUtil;
import com.bestcem.xm.om.grpc.v1.services.*;
import io.grpc.StatusRuntimeException;
import lombok.extern.slf4j.Slf4j;
import net.devh.boot.grpc.client.inject.GrpcClient;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

import static com.bestcem.bp.grpc.v1.base.Code.ERROR;

/**
 * @author ming.xue <ming.xue@idiaoyan.com>
 * @desc 倍市得联系人客户端
 * @date 2021-07-21
 */
@Slf4j
@Component("xmMemberClient")
public class XmMemberClient {

    @GrpcClient(GrpcClientNames.DS_USER)
    private UserServiceGrpc.UserServiceBlockingStub userServiceBlockingStub;

    @GrpcClient(GrpcClientNames.DS_USER)
    private UserGroupServiceGrpc.UserGroupServiceBlockingStub userGroupServiceBlockingStub;

    @GrpcClient(GrpcClientNames.DS_USER)
    private OrgServiceGrpc.OrgServiceBlockingStub orgServiceBlockingStub;

    @GrpcClient(GrpcClientNames.DS_USER)
    PackageServiceGrpc.PackageServiceBlockingStub packageServiceBlockingStub;

    public ServiceResult<List<String>> listOrgAdminIds(String orgId) {
        ListAdminsByOrgIdsRequest.Builder builder = ListAdminsByOrgIdsRequest.newBuilder();
        builder.addAllOrgIds(Collections.singletonList(orgId));
        ListAdminsByOrgIdsResponse response = null;
        try {
            response = userServiceBlockingStub.listAdminsByOrgIds(builder.build());
        } catch (StatusRuntimeException e) {
            String msg = String.format("根据组织id获取该公司下对应的权限id error, orgId: %s", orgId);
            log.error(msg, e);

//            if (GRpcUtil.shouldRetry(e.getStatus().getCode())) {
//                return ServiceResult.<List<String>>fail(msg).setErrorCode(ErrorCodes.B0002);
//            }
            return ServiceResult.fail(msg);
        }
        List<User> users = response.getUsersList();
        if (CollectionUtils.isEmpty(users)) {
            return ServiceResult.success(Collections.emptyList());
        }
        List<String> userIds = users.stream().map(User::getId).collect(Collectors.toList());
        return ServiceResult.success(userIds);
    }

    public ServiceResult<JSONObject> getStoreIdNameMap(String orgId) {
        int page = 1;
        int size = 10000;

        List<StoreIdName> list = listStoreIdNames(orgId, page, size);

        // 根据id去重
        JSONObject distinctUserGroups = new JSONObject();
        for (StoreIdName userGroup : list) {
            JSONObject groupJs = new JSONObject();
            groupJs.put("id", userGroup.getId());
            groupJs.put("name", userGroup.getName());
            groupJs.put("code", userGroup.getCode());
            if (!distinctUserGroups.containsKey(userGroup.getId())) {
                distinctUserGroups.put(userGroup.getId(), groupJs);
            }
        }

        return ServiceResult.success(distinctUserGroups);
    }

    private List<StoreIdName> listStoreIdNames(String orgId, int page, int size) {
        Page pageParam = Page.newBuilder().setPage(page).setSize(size).build();
        ListStoreIdNamesRequest request = ListStoreIdNamesRequest.newBuilder()
                .setPage(pageParam)
                .setOrgId(orgId).build();
        ListStoreIdNamesResponse response;
        try {
            response = userGroupServiceBlockingStub.listStoreIdNames(request);
        } catch (StatusRuntimeException e) {
            log.error("【联系人】根据orgId获取该组织下门店名称与门店id的映射失败，request:{}", request, e);
            throw new RuntimeException("【联系人】根据orgId获取该组织下门店名称与门店id的映射失败");
        }
        if (response.getStatus().getCodeValue() != Constants.SUCCESS) {
            log.error("【联系人】根据orgId获取该组织下门店名称与门店id的映射失败，response:{}", response);
            throw new RuntimeException("【联系人】根据orgId获取该组织下门店名称与门店id的映射失败");
        }
        return response.getStoresList();
    }

    public ServiceResult<Map<String, String>> getStoreNameAndIdMap(String orgId) {
        if (!StringUtils.hasText(orgId)) {
            return ServiceResult.fail("企业id异常");
        }
        Page pageParam = Page.newBuilder().setPage(1).setSize(10000).build();
        ListStoreIdNamesRequest request = ListStoreIdNamesRequest.newBuilder()
                .setPage(pageParam)
                .setOrgId(orgId).build();
        ListStoreIdNamesResponse response;

        try {
            response = userGroupServiceBlockingStub.listStoreIdNames(request);
        } catch (StatusRuntimeException e) {
            log.error("【联系人】据orgId获取该组织下门店名称与门店id的映射失败，request:{}", request, e);
            return ServiceResult.fail("【联系人】据orgId获取该组织下门店名称与门店id的映射失败");
        }
        if (response.getStatus().getCodeValue() != Constants.SUCCESS) {
            log.error("【联系人】据orgId获取该组织下门店名称与门店id的映射失败，response:{}", response);
            return ServiceResult.fail("【联系人】据orgId获取该组织下门店名称与门店id的映射失败");
        }
        List<StoreIdName> storesList = response.getStoresList();
        Map<String, String> storeIdNameMap = storesList.stream().collect(Collectors.toMap(StoreIdName::getId, StoreIdName::getName));

        // {"name","id"} 门店name-id映射
        HashMap<String, String> res = new HashMap<>(storeIdNameMap.size());
        for (Map.Entry<String, String> entry : storeIdNameMap.entrySet()) {
            if (entry.getValue() == null || !StringUtils.hasText(entry.getValue())) {
                continue;
            }
            // 此处暂不考虑重复
            res.put(entry.getValue(), entry.getKey());
        }
        return ServiceResult.success(res);
    }

    public ServiceResult<OrganizationDTO> getOrgByIdOrCode(String id, String code) {
        GetOrgByIdOrCodeRequest.Builder builder = GetOrgByIdOrCodeRequest.newBuilder();
        if (StrUtil.isNotEmpty(id)) {
            builder.setId(id);
        }

        if (StrUtil.isNotEmpty(code)) {
            builder.setCode(code);
        }

        GetOrgByIdOrCodeResponse response;
        try {
            response = orgServiceBlockingStub.getOrgByIdOrCode(builder.build());
        } catch (StatusRuntimeException e) {
            String msg = String.format("通过org_id或者org_code获取org error, id: %s, code: %s", id, code);
            log.error(msg, e);
//            if (GRpcUtil.shouldRetry(e.getStatus().getCode())) {
//                return ServiceResult.<OrganizationDTO>fail(msg).setErrorCode(ErrorCodes.B0002);
//            }
            return ServiceResult.fail(msg);
        }
        OrganizationDTO dto = responseToOrganizationDTO(response);
        return ServiceResult.success(dto);
    }

    public ServiceResult<List<GroupNodeDTO>> listAncestorGroups(String groupId) {
        ListAncestorStoresByIdRequest.Builder builder = ListAncestorStoresByIdRequest.newBuilder();
        builder.setGroupId(groupId);
        try {
            ListAncestorStoresByIdResponse response =
                    userGroupServiceBlockingStub.listAncestorStoresById(builder.build());
            if (Objects.isNull(response) || ERROR.equals(response.getStatus().getCode())) {
                log.error("[Ticket] USER listAncestorGroupsByGroupId {} Error; ErrorMsg: {}", groupId, response);
                return null;
            }
            return ServiceResult.success(groupBaseToGroupNodeDTOList(response.getStoresList()));
        } catch (Exception e) {
            log.error("[Ticket] USER listAncestorGroupsByGroupId {} Error; ErrorMsg: {}", groupId, e.getMessage(), e);
            return null;
        }
    }

    private static List<GroupNodeDTO> groupBaseToGroupNodeDTOList(List<GroupBase> groupBaseList) {
        List<GroupNodeDTO> groupNodeDTOList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(groupBaseList)) {
            for (GroupBase groupBase : groupBaseList) {
                GroupNodeDTO groupNodeDTO = toGroupNodeDTO(groupBase);
                if (Objects.nonNull(groupNodeDTO)) {
                    groupNodeDTOList.add(groupNodeDTO);
                }
            }
        }
        return groupNodeDTOList;
    }

    private static GroupNodeDTO toGroupNodeDTO(GroupBase groupBase) {
        if (Objects.isNull(groupBase)) {
            return null;
        }
        GroupNodeDTO groupNodeDTO = new GroupNodeDTO();
        groupNodeDTO.setId(groupBase.getId());
        groupNodeDTO.setSeq(groupBase.getSeq());
        groupNodeDTO.setCode(groupBase.getCode());
        groupNodeDTO.setTitle(groupBase.getName());
        return groupNodeDTO;
    }

    public ServiceResult<Integer> getUserPackageQuota(String orgId) {
        GetPackageQuotaRequest request = GetPackageQuotaRequest.newBuilder().setOrgId(orgId).build();
        GetPackageQuotaResponse response;
        try {
            response = packageServiceBlockingStub.getPackageQuota(request);
        } catch (StatusRuntimeException e) {
            log.error("【联系人】根据组织ID或套餐ID获取对应套餐的相关限额失败，request:{}", request, e);
            return ServiceResult.fail("【联系人】根据组织ID或套餐ID获取对应套餐的相关限额失败");
        }
        if (response.getStatus().getCodeValue() != Constants.SUCCESS) {
            log.error("【联系人】根据组织ID或套餐ID获取对应套餐的相关限额失败，response:{}", response);
            return ServiceResult.fail("【联系人】根据组织ID或套餐ID获取对应套餐的相关限额失败");
        }
        String pack = response.getQuota();
        JSONObject packObject = null;
        try {
            packObject = JSON.parseObject(pack);
            if (!packObject.containsKey(com.bestcem.xm.member.util.Constants.PACKAGE_KEY_MEMBER_IND_QUOTA)) {
                return ServiceResult.fail("缺少 member_ind_quota");
            }
        } catch (Exception e) {
            log.error("json {} 解析失败", pack, e);
            return ServiceResult.fail(e.getMessage());
        }
        return ServiceResult.success(packObject.getInteger(com.bestcem.xm.member.util.Constants.PACKAGE_KEY_MEMBER_IND_QUOTA));
    }

    public ServiceResult<List<String>> listPackageIdsByCode(String code, Integer category) {
        ListPackageIdsByCodeRequest request = ListPackageIdsByCodeRequest.newBuilder().setCode(code).setCategoryValue(category).build();
        ListPackageIdsByCodeResponse response;
        try {
            response = packageServiceBlockingStub.listPackageIdsByCode(request);
        } catch (StatusRuntimeException e) {
            log.error("【联系人】根据套餐code获取有该功能的套餐ID列表失败，request:{}", request);
            return ServiceResult.fail("【联系人】根据套餐code获取有该功能的套餐ID列表失败");
        }
        if (response.getStatus().getCodeValue() != Constants.SUCCESS) {
            log.error("【联系人】根据套餐code获取有该功能的套餐ID列表失败，response:{}", response);
            return ServiceResult.fail("【联系人】根据套餐code获取有该功能的套餐ID列表失败");
        }
        return ServiceResult.success(response.getIdsList());
    }

    private OrganizationDTO responseToOrganizationDTO(GetOrgByIdOrCodeResponse response) {
        Organization organization = response.getOrg();
        OrganizationDTO dto = new OrganizationDTO();
        dto.setCheckSmtpId(organization.getAuditSmtpId());
        dto.setCode(organization.getCode());
        dto.setContent(organization.getContent());
        dto.setCorporateWallet(organization.getWalletId());
        dto.setEmail(organization.getAdminEmail());
        dto.setExpiryDt(DateUtil.getDate(organization.getPackageExpireTime()));
        dto.setFooter(organization.getFooterValue());
        dto.setFreeExpiryDt(DateUtil.getDate(organization.getFreeExpireTime()));
        dto.setHasNotifySales(organization.getNotifySales());
        dto.setId(organization.getId());
        dto.setIndustryId(organization.getIndustryId());
        dto.setIsComplete(organization.getComplete());
        dto.setIsDeliverCheck(organization.getDeliverAudit());
        dto.setIsInner(organization.getInner());
        dto.setMobile(organization.getAdminPhone());
        dto.setName(organization.getName());
        dto.setOrgAdmin(organization.getAdminName());
        dto.setPaasConf(organization.getPaasConf());
        dto.setPackageId(organization.getPackageId());
        dto.setPrivatekeyId(organization.getPriId());
        dto.setPublicKey(organization.getPubFilePath());
        dto.setRootGroupList(Collections.singletonList(organization.getRootGroupId()));
        dto.setSkin(organization.getSkin());
        dto.setSmsPrice(organization.getSmsPrice());
        dto.setSource(organization.getSourceValue());
        dto.setSourceRemark(organization.getSourceRemark());
        dto.setStatus(organization.getStatusValue());
        return dto;
    }
}
